package kq

import (
	"context"
	"encoding/json"
	"fmt"

	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/mqueuex"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	enum "mall/service/backend/common/enum/user"
	"mall/service/backend/rmq/internal/svc"
	"mall/service/order/rpc/orderclient"
	"mall/service/user/rpc/userclient"

	"github.com/dtm-labs/client/dtmcli/dtmimp"
	"github.com/dtm-labs/client/dtmgrpc"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

var OrderRefundError = resultx.NewErrCode(resultx.ORDER_UPDATE_TRADE_STATE_FAILED)

/**
 * Listening to the payment flow status change notification message queue
 */
type ThirdPartPaymentRefundMq struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewThirdPartPaymentRefundMq(ctx context.Context, svcCtx *svc.ServiceContext) *ThirdPartPaymentRefundMq {
	return &ThirdPartPaymentRefundMq{
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ThirdPartPaymentRefundMq) Consume(_, val string) error {
	// 解析数据
	var message mqueuex.ThirdPartPaymentRefundMessage
	if err := json.Unmarshal([]byte(val), &message); err != nil {
		// logx.WithContext(l.ctx).Error("ThirdPartPaymentRefundMq.Consume Unmarshal err : %v , val : %s", err, val)
		logx.Errorw("ThirdPartPaymentRefundMq.Consume json.Unmarshal err", logx.Field("detail", err.Error()))
		return err
	}

	// 执行业务..
	if err := l.execService(&message); err != nil {
		logx.Errorw("ThirdPartPaymentRefundMq.execService err", logx.Field("detail", err.Error()),
			logx.Field("val", val), logx.Field("message", fmt.Sprintf("%+v", message)))
		return err
	}

	return nil
}

func (l *ThirdPartPaymentRefundMq) execService(message *mqueuex.ThirdPartPaymentRefundMessage) error {
	// logrus.Info(fmt.Sprintf("ThirdPartPaymentRefundMq execService message: %+v", message))

	if message.OutRefundNo == nil || message.OutTradeNo == nil || message.Total == nil || message.Refund == nil {
		return errors.Wrapf(OrderRefundError, "Failed to get paid order, message: %+v ", message)
	}

	order, err := l.svcCtx.OrderRpc.GetOrderBySn(l.ctx, &orderclient.GetOrderBySnReq{
		PaymentNo:   message.OutTradeNo,
		RefundNo:    message.OutRefundNo,
		WithPayment: pointy.GetPointer(uint32(1)),
		WithRefund:  pointy.GetPointer(uint32(1)),
	})
	// logrus.Info(fmt.Sprintf("ThirdPartPaymentRefundMq execService order: %+v", order))
	if err != nil {
		return errors.Wrapf(OrderRefundError, "Failed to get paid order err: %v , message: %+v ", err, message)
	}

	// if order.Id == nil || order.TradeState == nil || order.UserId == nil || order.GemAmount == nil || order.Sn == nil {
	if order.Id == nil || order.TradeState == nil || order.UserId == nil || order.Sn == nil {
		return errors.Wrapf(OrderRefundError, "Failed to get valid data of paid order: %+v ", order)
	}

	if len(order.Payments) > 0 && len(order.Refunds) > 0 {
		payment := order.Payments[0]
		refund := order.Refunds[0]
		if payment.Amount != nil && len(*payment.Amount) > 0 {
			if fa, err := moneyx.ParseDecimal(*payment.Amount); err != nil {
				return errors.Wrapf(OrderRefundError, "Failed to get paid amount err: %v , amount: %s ", err, *payment.Amount)
			} else {
				amount := moneyx.FormatDecimalToFen(fa)
				// 比对金额
				if amount != *message.Total {
					return errors.Wrapf(OrderRefundError, "Paid order amount exception, amount: %v , message: %v ", amount, message)
				}

				if payment.Status == nil || *payment.Status != globalkey.OrderTradeStateClosed {
					logrus.Info(fmt.Sprintf("ThirdPartPaymentRefundMq execService payment.Status exception: %d", *payment.Status))
					return nil
				}

				// Update the flow status.
				err = l.RefundDtmSaga(order.Id, pointy.GetPointer(globalkey.OrderTradeStateRefunded), order.TradeState, payment.Id, refund.Id, message.RefundId)
				if err != nil {
					return errors.Wrapf(OrderRefundError, "update order tradeState fail, err: %v , message: %+v", err, message)
				}
			}
		}
	}

	return nil
}

func (l *ThirdPartPaymentRefundMq) RefundDtmSaga(
	orderId *uint64,
	tradeState *uint32,
	tradeStateRevert *uint32,
	paymentId *uint64,
	refundId *uint64,
	refundTransactionId *string,
) error {
	// 获取 OrderRpc BuildTarget
	orderRpcBusiServer, err := l.svcCtx.Config.OrderRpc.BuildTarget()
	if err != nil {
		return err
		// return fmt.Errorf("下单异常超时")
	}

	// DefaultGrpcServer default url for grpc server.
	defaultGrpcServer := l.svcCtx.Config.DefaultGrpcServer

	// 创建一个gid
	gid := dtmgrpc.MustGenGid(defaultGrpcServer)

	// 创建一个saga协议的事务
	saga := dtmgrpc.NewSagaGrpc(defaultGrpcServer, gid).
		Add(
			orderRpcBusiServer+"/order.Order/RefundRaw",
			orderRpcBusiServer+"/order.Order/RefundRevert",
			&orderclient.UpdateTradeStateReq{
				Id:                  orderId,
				TradeState:          tradeState,
				TradeStateRevert:    tradeStateRevert,
				PaymentId:           paymentId,
				RefundId:            refundId,
				RefundTransactionId: refundTransactionId,
			})

	// 事务提交
	err = saga.Submit()
	dtmimp.FatalIfError(err)
	if err != nil {
		return err
		// return fmt.Errorf("submit data to dtm-server err : %+v \n", err)
	}

	return nil
}

func (l *ThirdPartPaymentRefundMq) RefundDtmSagaBak(
	orderId *uint64,
	tradeState *uint32,
	tradeStateRevert *uint32,
	paymentId *uint64,
	userId *uint64,
	amount *string,
	orderSn *string,
) error {
	// 获取 OrderRpc BuildTarget
	orderRpcBusiServer, err := l.svcCtx.Config.OrderRpc.BuildTarget()
	if err != nil {
		return err
		// return fmt.Errorf("下单异常超时")
	}

	// 获取 UserRpc BuildTarget
	userRpcBusiServer, err := l.svcCtx.Config.UserRpc.BuildTarget()
	if err != nil {
		return err
	}

	// DefaultGrpcServer default url for grpc server.
	defaultGrpcServer := l.svcCtx.Config.DefaultGrpcServer

	// 创建一个gid
	gid := dtmgrpc.MustGenGid(defaultGrpcServer)

	// 创建一个saga协议的事务
	saga := dtmgrpc.NewSagaGrpc(defaultGrpcServer, gid).
		Add(
			orderRpcBusiServer+"/order.Order/RefundRaw",
			orderRpcBusiServer+"/order.Order/RefundRevert",
			&orderclient.UpdateTradeStateReq{
				Id:               orderId,
				TradeState:       tradeState,
				TradeStateRevert: tradeStateRevert,
				PaymentId:        paymentId,
			}).
		Add(
			userRpcBusiServer+"/user.User/UpdateUserAssetRaw",
			userRpcBusiServer+"/user.User/UpdateUserAssetRevert",
			&userclient.UpdateUserAssetReq{
				UserId:       userId,
				AssetType:    pointy.GetPointer(enum.UserAssetTypeGem),            // 宝石
				ChangeType:   pointy.GetPointer(enum.UserAssetChangeTypeIncrease), // 增加
				ChangeAmount: amount,
				SourceType:   pointy.GetPointer(enum.UserAssetSourceTypeCharge), // 充值
				SourceId:     orderId,
				SourceDesc:   orderSn,
			})

	// 事务提交
	err = saga.Submit()
	dtmimp.FatalIfError(err)
	if err != nil {
		return err
		// return fmt.Errorf("submit data to dtm-server err : %+v \n", err)
	}

	return nil
}
